#include "cliread.h"
#include <QDateTime>
#include <QDebug>

namespace HIM {

bool CLIRead::readCLIFile(const QString& filePath)
{
    clearAll();
    cliFile_->setFileName(filePath);
    if(cliFile_->open(QIODevice::ReadOnly))
    {
        //emit cliReadProgress(5);
        qint64 cliFileSize = cliFile_->size();
        qDebug()<<"file size:"<<cliFileSize;
        qDebug()<<QDateTime::currentDateTime();
        cliDataPtr_ = cliFile_->map(0,cliFileSize);
        if(!cliDataPtr_){
            throw CliReadException("文件内存映射失败，请检查！");
            return false ;
        }else{
            auto cliData_ = cliDataPtr_;
            while (1){
                if(*cliData_ == '$'){
                    std::string token;
                    token+=*cliData_;
                    while(*(++cliData_)){
                        if(*cliData_=='/'){
                            token+=*cliData_;
                            break;
                        }else if(*cliData_ =='\r' || *cliData_ =='\n'){
                            break;
                        }else{
                            token+=*cliData_;
                        }
                    }
                    if(token.compare(HEADERSTART)==0){
                        cliDataIndex.header.first = cliData_ - cliDataPtr_-13;
                    }else if (token.compare(HEADEREND)==0) {
                        cliDataIndex.header.second = cliData_ - cliDataPtr_;
                    }else if (token.compare(GEOMETRYSTART)==0) {
                        cliDataIndex.geometry.first = cliData_ - cliDataPtr_-15;
                    }else if (token.compare(GEOMETRYEND)==0) {
                        cliDataIndex.geometry.second = cliData_ - cliDataPtr_;
                    }else if (token.compare(LAYER)==0) {
                        //bug FOCUS参数
                        cliDataIndex.layer.append(cliData_ - cliDataPtr_-7);
                    }else {
                        ++cliData_;
                        continue;
                    }
                }else if(*cliData_ == '\0' || !*cliData_) {
                    break;
                }else{
                    ++cliData_;
                }
            }

            //填充头部数据
            if(cliDataIndex.header.first!=-1&&cliDataIndex.header.second!=-1
                    &&cliDataIndex.header.first<cliDataIndex.header.second){
                analysisCLIHeader();
            }else{
                throw CliReadException("文件头部数据有误，请检查！");
            }

            if(cliDataIndex.layer.size()>2&&cliDataIndex.layer.at(0)>cliDataIndex.geometry.first
                    &&cliDataIndex.layer.last()<cliDataIndex.geometry.second
                    &&cliDataIndex.geometry.first<cliDataIndex.geometry.second){
                analysisCLILayer(1);
            }else{
                throw CliReadException("文件层数据有误，请检查！");
            }

            //TODO 打印时间预估
            printEstimatedTime_S = CLIREAD.getCliHeasderData()->layers*6 + cliFileSize/6000.;

            qDebug()<<QDateTime::currentDateTime();
            qDebug()<<"cliDataIndex.header.first :"<<cliDataIndex.header.first;
            qDebug()<<"cliDataIndex.header.second :"<<cliDataIndex.header.second;
            qDebug()<<"cliDataIndex.geometry.first :"<<cliDataIndex.geometry.first;
            qDebug()<<"cliDataIndex.geometry.second :"<<cliDataIndex.geometry.second;
            qDebug()<<"cliDataIndex.layer.size :"<<cliDataIndex.layer.size();

            //            for(auto i : cliDataIndex.layer){
            //                qDebug()<<"cliDataIndex.layer : " << i ;
            //            }
            cliLoaded = true;
            return true ;
        }
    }else{
        throw CliReadException("文件无法打开，请检查！");
        return false ;
    }
    cliFile_->close();
}

bool CLIRead::analysisCLIHeader()
{
    //解析
    std::string headerdStr(cliDataPtr_ + cliDataIndex.header.first, cliDataPtr_ +  cliDataIndex.header.second);
    QString headerData = QString::fromStdString(headerdStr);
    auto headerDataList = headerData.split("\r\n");
    for(auto i : headerDataList){
        //填充文件头数据
        if(i.contains(QString::fromStdString(HEADERSTART))){
            qDebug()<<"HEADERSTART: " <<i;
        }else if(i.contains(QString::fromStdString(ASCII))){
            cliHeasderData.format = QString::fromStdString(ASCII);
        }else if(i.contains(QString::fromStdString(BINARY))){
            cliHeasderData.format = QString::fromStdString(BINARY);
        }else if(i.contains(QString::fromStdString(UNITS))){
            if(!cliFloatRegex(i,cliHeasderData.units)){
                emit cliReadProgress(-1);
                throw CliReadException("文件单位数据错误，请检查！");
                return false ;
            };
        }else if(i.contains(QString::fromStdString(VERSION))){
            if(!cliIntRegex(i,cliHeasderData.version)){
                emit cliReadProgress(-1);
                throw CliReadException("文件版本数据错误，请检查！");
                return false ;
            };
        }else if(i.contains(QString::fromStdString(DATE))){
            if(!cliIntRegex(i,cliHeasderData.date)){
                emit cliReadProgress(-1);
                throw CliReadException("文件日期数据错误，请检查！");
                return false ;
            };
        }else if(i.contains(QString::fromStdString(DIMENSION))){
            if(!cliFloatsRegex(i,cliHeasderData.dimension)){
                emit cliReadProgress(-1);
                throw CliReadException("文件尺寸数据错误，请检查！");
                return false ;
            };
        }else if(i.contains(QString::fromStdString(LAYERS))){
            if(!cliIntRegex(i,cliHeasderData.layers)){
                emit cliReadProgress(-1);
                throw CliReadException("文件层总数错误，请检查！");
                return false ;
            };
        }else if(i.contains(QString::fromStdString(ALIGN))){
            if(!cliIntRegex(i,cliHeasderData.align)){
                emit cliReadProgress(-1);
                throw CliReadException("文件对齐位数错误，请检查！");
                return false ;
            };
        }else if(i.contains(QString::fromStdString(LABEL))){
            QPair<int,QString> result;
            if(!cliIntStrRegex(i,result)){
                emit cliReadProgress(-1);
                throw CliReadException("文件标签数据错误，请检查！");
                return false ;
            }else{
                cliHeasderData.label.push_back(result);
            };
        }else if(i.contains(QString::fromStdString(USERDATA))){
            qDebug()<<"HEADEREND: " <<i;
        }else if (i.contains(QString::fromStdString(HEADEREND))){
            qDebug()<<"HEADEREND: " <<i;
        }else{
            qDebug()<<"Unknown information : "<< i << " please check ";
        }
    }
    //    qDebug()<<"header :"<<headerData;
    //    qDebug()<<"cliHeasderData.format :"<<cliHeasderData.format;
    //    qDebug()<<"cliHeasderData.units :"<<cliHeasderData.units;
    //    qDebug()<<"cliHeasderData.version :"<<cliHeasderData.version;
    //    qDebug()<<"cliHeasderData.date :"<<cliHeasderData.date;
    //    qDebug()<<"cliHeasderData.layers :"<<cliHeasderData.layers;
    //    qDebug()<<"cliHeasderData.align :"<<cliHeasderData.align;

    return true;
}

bool CLIRead::analysisCLILayer(int layerIndex)
{
    QList<CliHetchesData>().swap(cliCurruntLayerData.hatchesList);
    cliCurruntLayerData.zPos=0;

    if(cliDataIndex.layer.size()>2&&layerIndex<cliDataIndex.layer.size()-1){
        std::string layerStr(cliDataPtr_ +cliDataIndex.layer[layerIndex], cliDataPtr_+cliDataIndex.layer[layerIndex+1]);

        QString layerData = QString::fromStdString(layerStr);
        auto layerDataList = layerData.split("\r\n",Qt::SkipEmptyParts);

        double curruntSpeed{0.0};
        double curruntPower{0.0};
        double curruntFocus{0.0};

        for(auto i : layerDataList){
            if(i.contains(QString::fromStdString(LAYER))){
                int zPos{0};
                if(!cliIntRegex(i,zPos)){
                    throw CliReadException("层高数据错误，请检查！");
                    return false ;
                }else{
                    cliCurruntLayerData.zPos = zPos*cliHeasderData.units;
                };
            }else if(i.contains(QString::fromStdString(POWER))){
                if(!cliFloatRegex(i,curruntPower)){
                    throw CliReadException("激光功率数据错误，请检查！");
                    return false ;
                };
            }else if(i.contains(QString::fromStdString(SPEED))){
                if(!cliFloatRegex(i,curruntSpeed)){
                    throw CliReadException("激光速度数据错误，请检查！");
                    return false ;
                };
            }else if(i.contains(QString::fromStdString(FOCUS))){
                if(!cliFloatRegex(i,curruntFocus)){
                    throw CliReadException("Focus数据错误，请检查！");
                    return false ;
                };
            }else if(i.contains(QString::fromStdString(HATCHES))){                
                QVector<int> result;
                if(!cliIntsRegex(i,result)){
                    throw CliReadException("填充线段数据错误，请检查！");
                    return false ;
                };
                CliHetchesData hetches;
                hetches.focus = curruntFocus;
                hetches.speed = curruntSpeed;
                hetches.power = curruntPower;
                hetches.label = result.at(0);
                hetches.lineNum = result.at(1);
                for(int i = 2; i < result.size()-3 ; i+=4 ){
                    //todo 线段标签提前判断
                    QPointF start(result.at(i)*cliHeasderData.units-150., result.at(i+1)*cliHeasderData.units-150.);
                    QPointF end(result.at(i+2)*cliHeasderData.units-150., result.at(i+3)*cliHeasderData.units-150.);
                    hetches.hatchVector.push_back(qMakePair(start,end));
                }
                cliCurruntLayerData.hatchesList.push_back(hetches);
            }else if(i.contains(QString::fromStdString(POLYLINE))){
                qDebug()<<"POLYLINE information : "<< i << " please check ";
            }else if(""==i){
                qDebug()<<"NULL information : "<< i << " please check ";
            }else{
                qDebug()<<"Unknown layer information : "<< i << " please check ";
            }
        }

        if(0==cliCurruntLayerData.zPos){
            qDebug()<<"cliCurruntLayerData zPos=0 err :";
            return false;
        }
        //        qDebug()<<"header :"<<layerData;
        //        qDebug()<<"curruntLayerData.zPos :"<<curruntLayerData.zPos;
        //        qDebug()<<"curruntLayerData.hatchesList.size() :"<<curruntLayerData.hatchesList.size();

        //        for(auto i : curruntLayerData.hatchesList){
        //            qDebug()<<"speed :"<<i.speed;
        //            qDebug()<<"power :"<<i.power;
        //            qDebug()<<"focus :"<<i.focus;
        //            qDebug()<<"label :"<<i.label;
        //            qDebug()<<"lineNum :"<<i.lineNum;
        //            qDebug()<<"hatchVector.size():"<<i.hatchVector.size();
        //            for(auto j : i.hatchVector){
        //                qDebug()<<"point:"<<j.first.x()<<","<<j.first.y()<<",:"<<j.second.x()<<","<<j.second.y();
        //            }
        //        }
        curruntLayerIndex = layerIndex;
        qDebug()<<"analysisCLILayer curruntLayerIndex :"<<curruntLayerIndex;
        return true;
    }else{
        qDebug()<<"analysisCLILayer err :";
        return false;
    }
}

bool CLIRead::cliFloatRegex(const QString &str , double &result)
{
    QRegExp floatRegex("-?\\d+\\.\\d+");
    if (str.indexOf(floatRegex) != -1) {
        result = floatRegex.cap(0).toDouble();
        return true;
    }else{
        return false ;
    }
}

bool CLIRead::cliFloatsRegex(const QString &str , QVector<double> &result)
{
    QRegExp floatsRegex("(-?\\d+\\.\\d+,?){1,}");
    if (str.indexOf(floatsRegex) != -1) {
        auto floatList = floatsRegex.cap(0).split(",");
        for(auto i:floatList){
            result.push_back(i.toDouble());
        }
        return true;
    }else{
        return false ;
    }
}

bool CLIRead::cliIntRegex(const QString &str , int &result)
{
    QRegExp intRegex("-?\\d+");
    if (str.indexOf(intRegex) != -1) {
        result = intRegex.cap(0).toInt();
        return true;
    }else{
        return false ;
    }
}

bool CLIRead::cliIntStrRegex(const QString &str , QPair<int,QString> &result)
{
    QRegExp intStrRegex("\\d+,.+");
    if (str.indexOf(intStrRegex) != -1) {
        auto IntStrList =  intStrRegex.cap(0).split(",");
        if(IntStrList.size()!=2){
            return false;
        }else{
            result.first = IntStrList.first().toInt();
            result.second = IntStrList.last();
            return true;
        }
    }else{
        return false ;
    }
}

bool CLIRead::cliIntsRegex(const QString &str , QVector<int> &result)
{
    QRegExp intsRegex("(\\d+,?){1,}");
    if (str.indexOf(intsRegex) != -1) {
        auto intList = intsRegex.cap(0).split(",");
        for(auto i:intList){
            result.push_back(i.toInt());
        }
        return true;
    }else{
        return false ;
    }
}

void CLIRead::clearAll()
{
    if(cliDataPtr_)
        cliFile_->unmap(cliDataPtr_);

    CliHeaderData cliHeasderDataClear;
    CliLayerData cliCurruntLayerDataClear;
    CliDataIndex cliDataIndexClear;

    cliHeasderData = cliHeasderDataClear;
    cliCurruntLayerData = cliCurruntLayerDataClear;
    cliDataIndex = cliDataIndexClear;

    curruntLayerIndex = 0;
    cliLoaded = false;
}


/*
emit cliReadProgress(8);

cliHeaderData = cliList.first();
//此处可以考虑使用策略模式和工厂模式


emit cliReadProgress(10);

auto cliGeometryList = cliList.last().split(LAYER);
//判断文件类型，给出不同的层数据解析接口
if(cliData.format==ASCII){
    for(auto i : cliGeometryList){

        int layer = 0 ;

        emit cliReadProgress(10);
    }
}else if(cliData.format == BINARY){
    //二进制解析

}else{
    emit cliReadProgress(-1);
    throw CliReadException("文件格式不支持，请检查！");
    return false ;
}


qDebug()<<QDateTime::currentDateTime();
return true;
}
*/

/*

    //此处开始写切片文件接口
    //加载时间要快
    //不全部加载到内存中
    //先全部解析一遍
    //用seek和lenth去获取其中的数据部分
    //测试一下速度
    //数据结构就用普通的结构体就行了

    //CLI文件数据
    //显示用
    //创建指令发送给RTC用  这两者是异步的

    //尝试一下内存映射
    //尝试一下KMP算法加速解析CLI文件


    QFile cliFile(filePath);
    if(cliFile.open(QIODevice::ReadOnly)){
        auto cliFilePtr_ = cliFile.map(0,cliFile.size(),QFile::MapPrivateOption);
        char* headerEnd_ = "$$HEADEREND";
        //进行字符串解析，解析出头数据和层key
        auto headerPtr_ = std::strstr((char *)cliFilePtr_,headerEnd_);
        char * data = malloc(headerPtr_-cliFilePtr_+1)



        auto headerStr = memcpy(cliFilePtr_,)


        //
        std::vector<int> layelKeys;
        while(std::strstr())



#include <stdio.h>
#include <string.h>

void computePrefixFunction(int* prefix, char* pattern, int pattern_length) {
    int i = 1;
    int len = 0;
    prefix[0] = 0;

    while (i < pattern_length) {
        if (pattern[i] == pattern[len]) {
            len++;
            prefix[i] = len;
            i++;
        } else {
            while (len > 0 && pattern[i] != pattern[len]) {
                len = prefix[len - 1];
            }
            if (len == 0) {
                prefix[i] = 0;
                i++;
            }
        }
    }
}

void KMPSearch(char* text, char* pattern) {
    int m = strlen(pattern);
    int n = strlen(text);

    int* prefix = (int*)malloc(sizeof(int) * m);
    computePrefixFunction(prefix, pattern, m);

    int i = 0;
    int j = 0;
    while (i < n) {
        if (j == m) {
            printf("找到子字符串在字符串中的位置：%d\n", i - j);
            j = prefix[m - 1];
        }

        if (text[i] == pattern[j]) {
            i++;
            j++;
        } else {
            if (j == 0) {
                i++;
            } else {
                j = prefix[j - 1];
            }
        }
    }
    free(prefix);
}


    }else{
        qCritical() << "Failed to open file:" << cliFile.errorString();
        return;
    }


*/
}

//            while ((cliDataPtr_ = std::strstr(cliDataPtr_, token))) {
//                printf("Substring found at position %d\n", pos + (current - str));
//                current += sub_len; // 移动到子字符串之后的位置，以便继续搜索
//                pos += (current - str);
//            }

//            QString lineStr;
//            for ( ; *cliDataPtr_ != NULL; cliDataPtr_++){
//                switch (*cliDataPtr_) {
//                case '\r' :{
//                    if(*(cliDataPtr_+1) ==  '\n'){

//                    }
//                }


//                if()
//               lineStr.append(*cliDataPtr_);
//            }



//            for ( ; *cliDataPtr_ != NULL; cliDataPtr_++)
//            {
//                switch (*cliDataPtr_) {
//                case '$' :{
//                    switch () {

//                    }




//                }

//                case '/' :{

//                }
//                case '\r' : {

//                }

//                case '\n' : {

//                }


//                }
//            }



//            while (*cliDataPtr_!=NULL) {


//               cliDataPtr_++;
//            }

//            throw CliReadException("文件单位数据错误，请检查！");




